package org.lex.ftplist.core.conf;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTPFile;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.lex.collection.tree.ITreeNode;
import org.lex.collection.tree.ITreeVisitor;
import org.lex.collection.tree.builder.NodeData;
import org.lex.collection.tree.builder.TreeBuilder;
import org.lex.ftplist.core.FtpUrl;
import org.lex.ftplist.core.Index;
import org.lex.ftplist.util.Conf;
import org.lex.ftplist.util.Constants;
import org.lex.ftplist.util.Xmls;
import org.lex.io.utils.FileUtils;
import org.lex.lang.PersistHelper;
import org.lex.string.XmlUtils;

public class ConfLoader {

    public static void loadIndeies(Map<Index, File> indexList) throws IOException, DocumentException {
        File[] files = Conf.getIndexFiles();
        for (File file : files) {
            Reader in = Conf.openFile(file);
            Document doc = null;
            try {
                doc = new SAXReader().read(in);
            } finally {
                IOUtils.closeQuietly(in);
            }
            Element root = doc.getRootElement();
            FtpUrl u = new FtpUrl();
            u.user = elementText(root, Xmls.User);
            u.password = elementText(root, Xmls.Password).toCharArray();
            u.host = elementText(root, Xmls.Host);
            u.port = Integer.parseInt(elementText(root, Xmls.Port));
            u.path = elementText(root, Xmls.Path);

            Index i = new Index();
            i.setUrl(u);
            i.setDate(new Date(Long.parseLong(root.attributeValue(Xmls.date))));

            indexList.put(i, file);
        }
    }

    public static void storeIndeies(Index index, File file) throws IOException {
        FileUtils.createFile(file);
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), Constants.ENCODING));

        Document doc = DocumentHelper.createDocument();
        Element root = doc.addElement(Xmls.Index);

        root.addAttribute(Xmls.date, Long.toString(index.getDate().getTime()));
        FtpUrl url = index.getUrl();
        root.addElement(Xmls.Host).setText(url.host);
        root.addElement(Xmls.Port).setText(Integer.toString(url.port));
        root.addElement(Xmls.User).setText(url.user);
        root.addElement(Xmls.Password).setText(new String(url.password));
        root.addElement(Xmls.Path).setText(url.path);
        String xml = XmlUtils.format(doc);
        out.write(xml);
        out.flush();
        out.close();
    }

    public static ITreeNode loadFTPList(File file) throws FileNotFoundException, UnsupportedEncodingException,
            DocumentException {
        Reader in = Conf.openFile(file);
        Document doc = new SAXReader().read(in);

        PersistHelper helper = new PersistHelper();
        List<NodeData> datas = new LinkedList<NodeData>();
        for (Iterator<Element> iter = doc.getRootElement().elementIterator(); iter.hasNext();) {
            Element e = iter.next();
            String id = e.attributeValue(Xmls.id);
            String parentId = e.attributeValue(Xmls.parentId);

            FTPFile ftp = Xmls.decodeFtpFile(e);
            datas.add(new NodeData(id, parentId, ftp));
        }
        return new TreeBuilder().buildTree(datas);
    }

    public static void storeFTPList(ITreeNode root, File file) throws UnsupportedEncodingException, IOException {
        FileUtils.createFile(file);
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), Constants.ENCODING));

        Document doc = DocumentHelper.createDocument();
        final Element rootEle = doc.addElement(Xmls.FTPList);
        root.accept(new ITreeVisitor() {

            private long id = 0;
            private PersistHelper helper = new PersistHelper();
            // <node, id>
            private Map<ITreeNode, String> map = new IdentityHashMap<ITreeNode, String>();

            @Override
            public void visit(ITreeNode node) {
                String thisId = Long.toString(id++);
                map.put(node, thisId);

                Element e = null;
                FTPFile file = (FTPFile) node.getData();
                if (null != file) {
                    e = Xmls.encodeFtpFile(file);
                } else {
                    e = rootEle.addElement(Xmls.Node);
                }
                e.addAttribute(Xmls.id, thisId);
                if (null != node.getParent()) {
                    e.addAttribute(Xmls.parentId, map.get(node.getParent()));
                }
                rootEle.add(e);
            }
        });
        String xml = XmlUtils.format(doc);
        out.write(xml);
        out.flush();
        out.close();
    }

    private static String elementText(Element parent, String childElementName) {
        Element e = parent.element(childElementName);
        if (null != e) {
            return e.getText();
        } else {
            return "";
        }
    }
}
